using System;
using System.IO;
using lucere.analysis.index;
using lucere.analysis.score;

namespace lucere.service.search
{
	///<summary>
	/// Expert: a FieldComparator compares hits so as to determine their
	/// sort order when collecting the top results with {@link
	/// TopFieldCollector}.  The concrete public FieldComparator
	/// classes here correspond to the SortField types.
	///
	/// <p>This API is designed to achieve high performance
	/// sorting, by exposing a tight interaction with {@link
	/// FieldValueHitQueue} as it visits hits.  Whenever a hit is
	/// competitive, it's enrolled into a virtual slot, which is
	/// an int ranging from 0 to numHits-1.  The {@link
	/// FieldComparator} is made aware of segment transitions
	/// during searching in case any internal state it's tracking
	/// needs to be recomputed during these transitions.</p>
	///
	/// <p>A comparator must define these functions:</p>
	///
	/// <ul>
	///
	///  <li> <see cref="Compare"></see> Compare a hit at 'slot a'
	///       with hit 'slot b'.
	///  </li>
	///  <li> <see cref="SetBottom"></see> This method is called by
	///       {@link FieldValueHitQueue} to notify the
	///       FieldComparator of the current weakest ("bottom")
	///       slot.  Note that this slot may not hold the weakest
	///       value according to your comparator, in cases where
	///       your comparator is not the primary one (ie, is only
	///       used to break ties from the comparators before it).
	///  </li>
	///  <li> <see cref="CompareBottom"></see> Compare a new hit (docID)
	///       against the "weakest" (bottom) entry in the queue.
	///  </li>
	///  <li> <see cref="Copy"></see> Installs a new hit into the
	///       priority queue.  The {@link FieldValueHitQueue}">
	///       calls this method when a new hit is competitive.
	///  </li>
	///  <li> <see cref="SetNextReader"></see> Invoked
	///       when the search is switching to the next segment.
	///       You may need to update internal state of the
	///       comparator, for example retrieving new values from
	///       the {@link FieldCache}.
	///  </li>
	///  <li> <see cref="Value"></see> Return the sort value stored in
	///       the specified slot.  This is only called at the end
	///       of the search, in order to populate {@link
	///       FieldDoc#fields} when returning the top results.  
	/// </li>
	/// </ul>
	///
	/// <b>NOTE:</b> This API is experimental and might change in
	/// incompatible ways in the next release.
	///</summary>
	public interface IFieldComparator
	{
		///<summary>
		/// Compare hit at slot1 with hit at slot2.
		/// </summary>
		/// <param name="slot1">first slot to compare</param>
		/// <param name="slot2">second slot to compare</param>
		/// <returns>any N less then 0 if slot2's value is sorted after</returns>
		int Compare(int slot1, int slot2);

		///<summary>
		/// Set the bottom slot, ie the "weakest" (sorted last)
		/// entry in the queue.  When <see cref="CompareBottom"></see> is
		/// called, you should compare against this slot.  This
		/// will always be called before <see cref="CompareBottom"></see>.
		/// </summary>
		/// <param name="slot"> the currently weakest (sorted last) slot in the queue</param>
		void SetBottom(int slot);


		///<summary>
		///Compare the bottom of the queue with doc.  This will
		///only invoked after setBottom has been called.  This
		///should return the same result as <see cref="Compare(int,int)"></see> as if bottom were slot1 and the new
		///document were slot 2.
		///   
		///<p>For a search that hits many results, this method
		///will be the hotspot (invoked by far the most
		///frequently).</p>
		///</summary>
		///<param name="doc"> that was hit</param>
		///<returns>
		///any  N less then 0 if the doc's value is sorted after
		///the bottom entry (not competitive), any N greater then 0 if the
		///doc's value is sorted before the bottom entry and 0 if
		///they are equal.
		///</returns>
		int CompareBottom(int doc);

		///<summary>
		/// This method is called when a new hit is competitive.
		///You should copy any state associated with this document
		/// that will be required for future comparisons, into the
		///specified slot.
		///</summary>
		///<param name="slot"> which slot to copy the hit to</param>
		///<param name="doc">docID relative to current reader</param>
		void Copy(int slot, int doc);

		///<summary>
		/// Set a new Reader. All doc correspond to the current Reader.
		///</summary>
		///<param name="reader">current reader</param>
		///<param name="docBase">docBase of this reader </param>
		///<exception cref="IOException"></exception>
		void SetNextReader(IIndexReader reader, int docBase);

		///<summary>
		/// Sets the Scorer to use in case a document's score is
		/// needed.
		///</summary>
		///<param name="scorer"> Scorer instance that you should use to
		///obtain the current hit's score, if necessary. 
		///</param>
		void SetScorer(IScorer scorer);

		///<summary>
		///Return the actual value in the slot.
		///</summary>
		///<param name="slot">the value</param>
		///<returns>value in this slot upgraded to Comparable</returns>
		IComparable Value(int slot);
	}
}